import { Button } from 'antd';
import { debounce, isEmpty } from 'lodash-es';
import { useEffect, useRef, useState } from 'react';
import { CSSTransition } from 'react-transition-group';
import { IconFont } from 'ym-design';
import './index.less';
import type { YmBackTopProps } from './interfrace';

function YmBackTop(props: YmBackTopProps) {
  const {
    visibilityHeight = 300,
    target,
    onSrollToTop,
    duration = 450,
    prefixCls = 'ym-back-top',
    backTopStyle,
  } = props;
  const [visible, setVisible] = useState(false);
  const backTopTransitionRef = useRef(null);
  const scrollTarget = useRef<any>(null);
  const rafIdRef = useRef<number>();
  //防抖只会在最后一次事件后执行触发函数，节流不管事件多么的频繁，都会保证在规定时间段内触发事件函数,知道所有触发的事件执行完毕。
  const handleScroll = debounce(() => {
    setVisible(scrollTarget.current.scrollTop >= visibilityHeight);
  }, 500);

  const requestAnimFrame = (function () {
    return (
      window.requestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      function (callback) {
        return window.setTimeout(callback, 1000 / 60); //大多数屏幕渲染的时间间隔是每秒60帧
      }
    );
  })();

  const cancelAnimFrame = (function () {
    return (
      window.cancelAnimationFrame ||
      window.webkitCancelAnimationFrame ||
      window.mozCancelAnimationFrame ||
      function (rafIdParams) {
        window.clearInterval(rafIdParams);
      }
    );
  })();

  /**
   *计算duration之内终点位置
   * @param {*} t 间隔时间
   * @param {*} b 起点距离
   * @param {*} c 要移动的距离
   * @param {*} d 花费时间
   * @returns
   */
  const easeInOutQuad = (t: number, b: number, c: number, d: number) => {
    t /= d / 2;
    if (t < 1) {
      return (c / 2) * t * t + b;
    }
    t--;
    return (-c / 2) * (t * (t - 2) - 1) + b;
  };

  function _scrollTo(end: number, duration: number, callback?: () => void) {
    const start = scrollTarget.current.scrollTop;
    const change = end - start;
    const increment = 20;
    let currentTime = 0;
    duration = typeof duration === 'undefined' ? 500 : duration;
    const animateScroll = function () {
      // increment the time
      currentTime += increment;
      // find the value with the quadratic in-out easing function
      const curEnd = Math.floor(
        easeInOutQuad(currentTime, start, change, duration),
      );
      // console.log('---curEnd--:', curEnd);
      scrollTarget.current.scrollTo(start, curEnd);
      // do the animation unless its over
      if (currentTime < duration) {
        rafIdRef.current = requestAnimFrame(animateScroll); //浏览器其实一直在刷新，当给window.requestAnimationFrame传入一个回调函数的时候，那么就是告诉浏览器在渲染前执行一下这个回调函数。
      } else {
        cancelAnimFrame(rafIdRef.current!);
        if (callback && typeof callback === 'function') {
          // the animation is done so lets callback
          callback();
        }
      }
    };
    animateScroll();
  }

  //滚动到顶部
  const handleScrollTop = () => {
    // console.log('--scrollTarget3--:', scrollTarget.current.scrollTop);
    if (!scrollTarget.current) return;
    // scrollTarget.current.scrollTo(scrollTarget.current.scrollTop, 0);
    _scrollTo(0, duration, onSrollToTop);
  };

  useEffect(() => {
    const container: any = target || document.documentElement; //html
    // console.log('--container--:', container);
    if (!isEmpty(container)) {
      scrollTarget.current = container;
      container.addEventListener('scroll', handleScroll);
      return () => {
        container?.removeEventListener('scroll', handleScroll);
      };
    }
  }, []);

  return (
    //CSSTransition: 根据 children的 enter和exit给children添加class, 当 in=== false时 CSSTransition 包裹下的dom消失，
    //
    <CSSTransition
      nodeRef={backTopTransitionRef}
      in={visible}
      timeout={300}
      unmountOnExit
      classNames="transition_node"
    >
      <div
        className={prefixCls}
        style={backTopStyle}
        ref={backTopTransitionRef}
      >
        <Button
          type="default"
          shape="circle"
          block
          icon={<IconFont type="icon-zhiding1" />}
          style={{ height: '40px', border: 'none' }}
          onClick={handleScrollTop}
        />
      </div>
    </CSSTransition>
  );
}

export default YmBackTop;
